home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 2
/
Gold Medal Software Volume 2 (Gold Medal) (1994).iso
/
archive
/
ntzip.arj
/
IMPLODE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-03-26
|
9KB
|
287 lines
/*
Copyright (C) 1990,1991 Mark Adler, Richard B. Wales, and Jean-loup Gailly.
Permission is granted to any individual or institution to use, copy, or
redistribute this software so long as all of the original files are included
unmodified, that it is not sold for profit, and that this copyright notice
is retained.
*/
/*
* implode.c by Richard B. Wales.
*
* PURPOSE
*
* Compress an input file using the ZIP "implosion" method.
*
* DISCUSSION
*
* The "implosion" algorithm is a composite of (1) OPM/L compres-
* sion within a sliding window, and (2) variable-length binary
* encoding of various parts of the OPM/L output.
*
* For a detailed treatment of OPM/L compression, see the source
* file "im_lmat.c".
*
* For a detailed treatment of variable-length binary encoding,
* see the source file "im_ctree.c".
*
* Since Pass Two (binary encoding) depends on a statistical anal-
* ysis of the entire output of Pass One (OPM/L compression), the
* Pass One output is saved in a temporary file and re-read for
* Pass Two. Implosion is thus a two-pass algorithm.
*
* An outline of the algorithm follows:
*
* (1) The entire input file is read and compressed via the OPM/L
* technique. The OPM/L output is saved in a temporary file.
*
* (2) The compressed info from (1) is analyzed, and various fre-
* quency counts are tallied.
*
* (3) Based on the frequency counts, a decision is made as to
* whether or not the "literal" characters (those not matched
* in earlier parts of the input) should be represented via a
* binary code tree or left "as is". If there are not very
* many literal characters, or if their frequency distribution
* is fairly even, the number of bits saved through coding may
* be exceeded by the amount of info which must be included to
* describe the tree.
*
* (4) The temporary file from (1) is re-read. The information is
* further compressed via the binary code trees, and the result
* is sent to the ZIP output file.
*
* REFERENCES
*
* APPNOTE.TXT documentation file in PKZIP 1.10 distribution.
*
* See also references in the "im_lmat.c" and "im_ctree.c" source
* files.
*
* INTERFACE
*
* int imp_setup (long filesize, int pack_level)
* Initialize the "implode" routines for a new file.
*
* int imp_p1 (char *buf, int count)
* Process "count" input characters pointed to by "buf". This
* routine is called as many times as needed to process the
* entire input file. There is no upper limit on "count".
*
* int imp_size (long *size, char *opts)
* Terminate processing of the input file, and return the com-
* pressed size ("size") and implosion option flags ("opts").
*
* int imp_p2 (FILE *outfp)
* Output the entire compressed file -- including S-F trees and
* data -- to the ZIP output file "outfp".
*
* int imp_clear (void)
* Clean up after processing and outputting a file. This rou-
* tine may be called at any time to abort further processing.
*
* All the above routines return zero if successful, or a non-zero
* value if there was an error.
*/
#include "implode.h"
#include "ziperr.h"
/***********************************************************************
*
* Error return codes for the main ZIP program.
* Most of these are in "ziperr.h".
*/
#define ZE_MAP(err) \
( ((err) == IM_OK) ? ZE_OK \
: ((err) == IM_NOMEM) ? ZE_MEM \
: ((err) == IM_IOERR) ? ZE_TEMP \
: (fprintf(stderr,"\nZE_MAP(%d)",(err)), \
ZE_LOGIC))
/***********************************************************************
*
* State variable for the implosion routines.
*/
#define IMP_SETUP 0 /* need to do "imp_setup" */
#define IMP_P1 1 /* setup done, ready for Pass 1 */
#define IMP_P2 2 /* Pass 1 done, ready for Pass 2 */
#define IMP_CLEAR 3 /* Pass 2 done, ready for "imp_clear" */
local int imp_state = IMP_SETUP;
/***********************************************************************
*
* Global variables.
*/
FDATA fd;
/***********************************************************************
*
* Set up for performing implosion on a new file.
*/
int
imp_setup (filesize, pack_level)
long filesize; /* input file size */
int pack_level; /* 0 = best speed, 9 = best compression, other = default */
{
ImpErr retcode;
extern char *tempname();
if (imp_state != IMP_SETUP)
{ fprintf (stderr, "\nimp_setup called with wrong state %d",
imp_state);
return ZE_LOGIC;
}
imp_state = IMP_P1;
/* Set up the initial parameters. Use an 8K window if the input
* file is greater than or equal to 5.5K, a 4K window otherwise.
*/
fd.fd_bufsize = 8192;
if (filesize < 5632) fd.fd_bufsize = 4096;
fd.fd_strsize = 320;
fd.fd_nbits = (fd.fd_bufsize == 4096) ? 6 : 7;
/* Create a temporary file for the Pass One output. */
fd.fd_temp = topen ('I');
if (fd.fd_temp == NULL)
return ZE_MEM;
/*
* Initialize the "longest match" routines.
* "ct_init" is called at this point because the "lm_input" routine
* (called in "imp_p1") calls the "ct_tally" routine.
*/
retcode = lm_init (pack_level);
if (retcode != IM_OK) return ZE_MAP (retcode);
retcode = ct_init ();
return ZE_MAP (retcode);
}
/***********************************************************************
*
* Feed characters to the implosion computation.
* This routine is called as many times as needed, until the entire
* input file has been processed.
*/
int
imp_p1 (buf, count)
char *buf; /* input characters */
int count; /* character count */
{ ImpErr retcode;
if (imp_state != IMP_P1)
{ fprintf (stderr, "\nimp_p1 called with wrong state %d",
imp_state);
return ZE_LOGIC;
}
if (buf == NULL || count < 0)
{ fprintf (stderr, "\nimp_p1 called with bad arguments");
return ZE_LOGIC;
}
retcode = lm_input ((U_CHAR *) buf, (U_INT) count);
return ZE_MAP (retcode);
}
/***********************************************************************
*
* Terminate processing of input for this file, and determine the size
* this file will have if it is imploded. Also, find out whether two
* or three S-F trees will be used (needed for directory entries).
*/
int
imp_size (size, opts)
long *size; /* imploded size */
char *opts; /* implosion option info */
{ ImpErr retcode;
if (imp_state != IMP_P1)
{ fprintf (stderr, "\nimp_size called with wrong state %d",
imp_state);
return ZE_LOGIC;
}
imp_state = IMP_P2;
if (size == NULL || opts == NULL)
{ fprintf (stderr, "\nimp_size called with bad arguments");
return ZE_LOGIC;
}
retcode = lm_windup ();
if (retcode != IM_OK) return ZE_MAP (retcode);
retcode = ct_mktrees ();
if (retcode != IM_OK) return ZE_MAP (retcode);
*size = fd.fd_clen;
*opts = (char)(((fd.fd_bufsize == 8192) ? 0x02 : 0)
| ((fd.fd_method == LITERAL_TREE) ? 0x04 : 0));
return ZE_OK;
}
/***********************************************************************
*
* Output the imploded version of the file (but not the file directory
* info) to the ZIP file.
*/
int
imp_p2 (outfp)
FILE *outfp; /* output (ZIP) file */
{ ImpErr retcode;
if (imp_state != IMP_P2)
{ fprintf (stderr, "\nimp_p2 called with wrong state %d",
imp_state);
return ZE_LOGIC;
}
imp_state = IMP_CLEAR;
if (outfp == NULL)
{ fprintf (stderr, "\nimp_p2 called with bad arguments");
return ZE_LOGIC;
}
retcode = ct_wrtrees (outfp);
if (retcode != IM_OK) return ZE_MAP (retcode);
retcode = ct_wrdata (outfp);
if (retcode != IM_OK) return ZE_MAP (retcode);
fflush (outfp);
if (ferror (outfp)) return ZE_TEMP;
return ZE_OK;
}
/***********************************************************************
*
* Clean up after doing an implosion.
* This routine may also be called at any time to abort an implosion.
*/
int
imp_clear ()
{ (void) lm_windup ();
if (fd.fd_temp != NULL)
(void) tclose (fd.fd_temp);
(void) ct_windup ();
imp_state = IMP_SETUP;
return ZE_OK;
}
/**********************************************************************/